parser grammar FlexParser;

options {
    tokenVocab = FlexLexer;
}

@parser::header {
    package pl.practica5;
}

@parser::members {

  List<RecognitionException> errors = new ArrayList<RecognitionException>();

  public List<RecognitionException> getAllErrors() {
      return new ArrayList<RecognitionException>(errors);
  }
 
  public boolean hasErrors() {
      return !errors.isEmpty();
  }
  
  @Override
  public void reportError(RecognitionException e) {
      displayRecognitionError(this.getTokenNames(), e);
      errors.add(e);
  }
  
}


// Analizador Sintactico
flex: definiciones SEPARA_BLOQUE reglas SEPARA_BLOQUE funciones EOF;


//------------------------------------------------------------------------------------------//

definiciones: defineTokens seccionDefinicionIds;

defineTokens: (definicionToken)+;
definicionToken: id rango;

rango: rangoTipo1 | rangoTipo2;
rangoTipo1: CORCHETE_ABIERTO (LETRA_MAYUSCULA | LETRA_MINUSCULA)+ CORCHETE_CERRADO; //[acvD]
rangoTipo2: CORCHETE_ABIERTO (rango1 | rango2 | rango3)+  CORCHETE_CERRADO; //[4-5] [A-H4-7]
rango1: DIGITO GUION DIGITO; // 4-7
rango2: LETRA_MAYUSCULA GUION LETRA_MAYUSCULA; // A-H
rango3: LETRA_MINUSCULA GUION LETRA_MINUSCULA; // b-s

seccionDefinicionIds: DECLARACION_ABIERTA definicionId+ DECLARACION_CERRADA;
definicionId: (tipo | id) id PUNTO_COMA;
tipo: (CHAR | DOUBLE | FLOAT | INT | LONG | VOID);
id: (ID | LETRA_MINUSCULA);
numero: (NUMERO | DIGITO);

//------------------------------------------------------------------------------------------//

reglas: regla+;

regla: expresion accion; 

expresion: (base | disyuncion)+;
disyuncion: PARENTESIS_ABIERTO base DISYUNCION base PARENTESIS_CERRADO operador?;
base: LLAVE_ABIERTA id LLAVE_CERRADA operador?;
operador: MAS | ASTERISCO | INTERROGACION;

accion: id (INCREMENTAR | DECREMENTAR) PUNTO_COMA;

//------------------------------------------------------------------------------------------//

funciones: funcion+;

funcion: cabeceraFuncion LLAVE_ABIERTA bloqueSentencias LLAVE_CERRADA;

bloqueSentencias: (sentencias)+;
sentencias: (sentenciaReturn | sentenciaAsignacion | sentenciaLlamada) PUNTO_COMA;

sentenciaReturn: RETURN numero;
sentenciaAsignacion: id IGUALAR (numero | pseudoSentenciaFOpen);
sentenciaLlamada: id PARENTESIS_ABIERTO (llamadaNormal | llamadaPrintf) PARENTESIS_CERRADO;
pseudoSentenciaFOpen: id PARENTESIS_ABIERTO id (CORCHETE_ABIERTO numero CORCHETE_CERRADO)? COMA STRING PARENTESIS_CERRADO;
llamadaNormal: (id (COMA id)*)?;
llamadaPrintf: STRING COMA id;


cabeceraFuncion: (tipo | id) id PARENTESIS_ABIERTO listaParametrosCabecera? PARENTESIS_CERRADO;
listaParametrosCabecera: VOID | noVacia;
noVacia: parametro (COMA parametro)*;
parametro: (tipo | id) ASTERISCO? id (CORCHETE_ABIERTO CORCHETE_CERRADO)?;